package com.example.websocketdemo.hander;


import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Slf4j // Lombok注解，自动生成日志对象
@Component
public class VideoOnlineHandler extends TextWebSocketHandler {

    // 核心数据结构：用于存储每个视频的在线连接
    // key: videoId, value: 一个线程安全的Session集合
    private static final Map<String, Set<WebSocketSession>> videoSessions = new ConcurrentHashMap<>();

    /**
     * 当新客户端连接时触发
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 从连接的URI中获取videoId参数
        // 例如: ws://localhost:8080/ws/video?videoId=123
        String videoId = getVideoIdFromUri(session.getUri().getQuery());
        if (videoId == null) {
            log.error("连接失败：未提供 videoId 参数。");
            session.close(CloseStatus.POLICY_VIOLATION.withReason("videoId is required"));
            return;
        }

        log.info("客户端 {} 连接到视频 {}", session.getId(), videoId);

        // 使用 computeIfAbsent 原子地获取或创建一个新的Session集合
        videoSessions.computeIfAbsent(videoId, k -> new CopyOnWriteArraySet<>()).add(session);

        // 连接成功后，立即广播一次最新的在线人数
        broadcastOnlineCount(videoId);
    }

    /**
     * 当客户端断开连接时触发
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String videoId = getVideoIdFromUri(session.getUri().getQuery());
        if (videoId == null) {
            return;
        }

        log.info("客户端 {} 离开视频 {}", session.getId(), videoId);

        // 从集合中移除Session
        Set<WebSocketSession> sessions = videoSessions.get(videoId);
        if (sessions != null) {
            sessions.remove(session);
            // 如果该视频的在线人数变为0，可以从Map中移除，释放内存
            if (sessions.isEmpty()) {
                videoSessions.remove(videoId);
            }
        }

        // 广播更新后的在线人数
        broadcastOnlineCount(videoId);
    }

    /**
     * 当收到客户端消息时触发 (本案例暂时不需要处理消息)
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("收到来自客户端 {} 的消息: {}", session.getId(), message.getPayload());
        // 可以在这里处理客户端发来的自定义消息
    }

    /**
     * 向指定视频的所有在线客户端广播最新的在线人数
     * @param videoId 视频ID
     */
    private void broadcastOnlineCount(String videoId) {
        Set<WebSocketSession> sessions = videoSessions.get(videoId);
        if (sessions == null || sessions.isEmpty()) {
            return; // 没有在线用户，无需广播
        }

        int count = sessions.size();
        // 构建要发送的JSON消息
        String message = String.format("{\"type\":\"COUNT_UPDATE\", \"count\":%d}", count);
        TextMessage textMessage = new TextMessage(message);

        // 遍历所有会话并发送消息
        for (WebSocketSession session : sessions) {
            // 确保会话是打开的
            if (session.isOpen()) {
                try {
                    // 使用 sendMessage() 发送消息
                    session.sendMessage(textMessage);
                } catch (IOException e) {
                    log.error("向 session {} 发送消息失败: {}", session.getId(), e.getMessage());
                }
            }
        }
        log.info("已向视频 {} 的 {} 个在线用户广播人数。", videoId, count);
    }

    /**
     * 从URI查询参数中提取videoId
     * @param query "videoId=123"
     * @return "123" 或 null
     */
    private String getVideoIdFromUri(String query) {
        if (query != null && query.contains("videoId=")) {
            return query.split("videoId=")[1];
        }
        return null;
    }
}